package com.xd.core.api.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xd.common.constant.SysConstant;
import com.xd.common.exception.XkdException;
import com.xd.common.util.AESUtil;
import com.xd.common.util.OrderNumUtil;
import com.xd.common.util.Sm4Util;
import com.xd.core.api.dto.*;
import com.xd.core.api.entity.BeneficiaryElectronic;
import com.xd.core.api.entity.ElectronicAccounts;
import com.xd.core.api.http.Signer;
import com.xd.core.api.http.Verifier;
import com.xd.core.api.mapper.BeneficiaryElectronicMapper;
import com.xd.core.api.mapper.ChannelPayTowMapper;
import com.xd.core.api.mapper.ElectronicAccountsMapper;
import com.xd.core.api.service.ApiService;
import com.xd.core.api.service.DLApiService;
import com.xd.core.api.util.HttpUtil;
import com.xd.core.api.util.JXMConvertUtil;
import com.xd.core.api.vo.BalanceVo;
import com.xd.core.api.vo.TowBalanceVo;
import com.xd.core.business.entity.*;
import com.xd.core.business.mapper.*;
import com.xd.core.company.dto.RegisterDto;
import com.xd.core.company.entity.*;
import com.xd.core.company.mapper.*;
import com.xd.core.company.service.ICompanyService;
import com.xd.core.system.mapper.ProvincesInfoMapper;
import com.xd.core.system.service.FileService;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class ApiServiceImpl implements ApiService {
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private OutInfoMapper outInfoMapper;
    @Autowired
    private CompanyAccountMapper companyAccountMapper;
    @Autowired
    private ProvincesInfoMapper provincesInfoMapper;
    @Autowired
    private ElectronicTransferInfoMapper electronicTransferInfoMapper;
    @Autowired
    private ElectronicAccountsMapper electronicAccountsMapper;
    @Autowired
    private ChannelTowRechargeMapper channelTowRechargeMapper;
    @Autowired
    private BeneficiaryElectronicMapper beneficiaryElectronicMapper;
    @Autowired
    private OfflineTransferInfoMapper offlineTransferInfoMapper;
    @Autowired
    private ICompanyService iCompanyService;
    @Autowired
    private DLApiService dlApiService;
    @Autowired
    private BindBankMapper bindBankMapper;
    @Autowired
    private OutOrderInfoMapper outOrderInfoMapper;
    @Autowired
    private CertificationOrderMapper certificationOrderMapper;
    @Autowired
    private CertificationMapper certificationMapper;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private FileService fileService;
    @Value("${aes.key}")
    private String aesKey;
    @Value("${gongzheng.notifyAppid}")
    private String notifyAppid;
    @Value("${gongzheng.notifySm4key}")
    private String notifySm4key;
    @Value("${image.registerAccount}")
    private String registerAccount;
    @Value("${image.localPathDir}")
    private String localPathDir;
    @Value("${baofu.appid}")
    private String APPID;
    @Value("${baofu.baseUrl}")
    private String baseUrl;
    @Value("${baofu.signtype}")
    private String SIGNTYPE;
    @Value("${baofu.version}")
    private String VERSION;
    @Value("${baofush.loans_out_no}")//小贷商户放款电子账户
    private String loans_out_no;
    //代理资方用到的密码
    @Value("${baofu.pfxPathPassword}")
    private String pfxPathPassword;
    @Value("${baofu.registerCallbackUrl}")
    private String registerCallbackUrl;
    @Value("${baofu.transferOrderReturn}")
    private String transferOrderReturn;
    @Value("${baofu.withdrawDepositReturn}")
    private String withdrawDepositReturn;
    @Value("${baofu.allotReturn}")
    private String allotReturn;
    @Value("${baofu.outAmountAllotReturn}")
    private String outAmountAllotReturn;
    @Value("${image.contract}")
    private String contractUrl;
    @Value("${image.uploadMortgageInfo}")
    private String uploadMortgageInfo;//上传客户抵押信息


    @Autowired
    private RedissonClient redissonClient;
    private final static String transferOrderLock = "TransferOrder";
    private static final int maxRetry = 10;//最大尝试机制
    private static final int sleepMillis = 1000;//休眠时间
    //可以动态配置文件
//    private final static String pfxPath = System.getProperty("user.dir") + "/resources/keyfile_pri.pfx";
//    private final static String pfxPath = System.getProperty("user.dir") + "/resources/pri.pfx";
    //随着JAR包 文件改变需要重新打包
    private final static String pfxPath = ApiServiceImpl.class.getClassLoader().getResource("keyfile_pri.pfx").getPath();
    //    private final static String cerPath = System.getProperty("user.dir") + "/resources/client_pub.cer";
    private final static String cerPath = ApiServiceImpl.class.getClassLoader().getResource("client_pub.cer").getPath();
    @Autowired
    private ChannelPayTowMapper channelPayTowMapper;
    @Autowired
    private IncomingInfoMapper incomingInfoMapper;
    private static final String towBaofuwithdrawLock = "towBaofuwithdrawLock_";//渠道二提现


    public String uploadFile(File file) throws Exception {
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2107";

        Map<String, File> fileMap = new HashMap<>();
        fileMap.put("file", file);
        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", "");
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(fileMap.toString()));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:{}", reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:{}", sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：{}", requestData);
        String results = HttpUtil.doUploadFile(fileMap, baseUrl, requestData);
        log.info("响应结果：{}", results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("机构注册接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：{}", signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果{}", bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果{}", s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        return jsonObject.getString("file_no");
    }

    @Override
    public Map<String, String> upload(MultipartFile multipartFile, Integer companyId) throws Exception {
        File file = multipartFileToFile(multipartFile, companyId);
        String fileNo = uploadFile(file);
        HashMap<String, String> map = new HashMap<>();
        map.put("fileNo", fileNo);
        map.put("filePath", registerAccount + "/" + file.getName());
        return map;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void prestoreRegisterResult(String app_id,
                                       String sign_type,
                                       String client_trans_id,
                                       String trans_timestamp,
                                       String trans_type,
                                       String callback_url,
                                       String version,
                                       String data,
                                       String sign) throws Exception {
        //验签
        JSONObject jsonObject = getData(app_id, sign_type, client_trans_id, trans_timestamp, trans_type, callback_url, version, data, sign);

        String auditStatus = jsonObject.getString("audit_status");
        String auditInfo = jsonObject.getString("audit_info");
        String accountNo = jsonObject.getString("account_no");
        String htAccountNo = jsonObject.getString("htAccount_no");

        ElectronicAccounts electronicAccounts = electronicAccountsMapper.selectOne(new LambdaQueryWrapper<ElectronicAccounts>().eq(ElectronicAccounts::getClientTransId, client_trans_id));
        Integer companyId = electronicAccounts.getCompanyId();

        if (auditStatus.equals("SUCCESS")) {//审核成功
            //修改公司状态 电子账户卡号
            companyAccountMapper.updatePrestore(companyId, accountNo, htAccountNo, SysConstant.ACCOUNT_APPLY_STATUS_THREE);
            //入库绑卡信息表
            Company company = companyMapper.selectById(companyId);
            CompanyAccount companyAccount = companyAccountMapper.selectById(companyId);
            BindBank bindBank = new BindBank();
            bindBank.setCompanyId(companyId);
            bindBank.setWalletNo(companyAccount.getPrestoreNo());
            bindBank.setAccNo(company.getBankAccount());
            bindBank.setAccName(company.getCompanyName());
            bindBank.setBankCode(company.getInterbankAccount());
            bindBank.setBankName(company.getOpeningBank());
            bindBankMapper.insert(bindBank);
        } else {//审核失败
            //删除申请资料
//            electronicAccountsMapper.delete(new LambdaQueryWrapper<ElectronicAccounts>().eq(ElectronicAccounts::getClientTransId, client_trans_id));
            companyAccountMapper.updatePrestoreRemark(companyId, auditInfo, SysConstant.ACCOUNT_APPLY_STATUS_FOUR);
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void prestoreRegister(RegisterDto registerDto) throws IOException {
        /*
         * 查询企业
         * */
        Company company = companyMapper.selectById(registerDto.getCompanyId());
        CompanyAccount companyAccount = companyAccountMapper.selectById(registerDto.getCompanyId());
        String applyStatus = null;
        if (companyAccount != null) {
            applyStatus = companyAccount.getPrestoreApplyStatus();
            if (applyStatus.equals(SysConstant.ACCOUNT_APPLY_STATUS_THREE)) {
                throw new XkdException("已申请,无法重复申请");
            }
        }
        String walletNo = register(registerDto, company, registerCallbackUrl);
        //修改企业机构编号
        companyAccountMapper.updatePrestoreNo(registerDto.getCompanyId(), registerDto.getFilePath(), SysConstant.ACCOUNT_APPLY_STATUS_TOW, walletNo);
    }


    @Transactional(rollbackFor = Exception.class)
    public String register(RegisterDto registerDto, Company company, String backUrl) throws IOException {
        ElectronicAccounts oldElectronicAccounts = electronicAccountsMapper.selectOne(new LambdaQueryWrapper<ElectronicAccounts>().eq(ElectronicAccounts::getCompanyId, company.getId()));
        //如果是第二次申请则用以前的流水号
        String client_trans_id = null;
        if (oldElectronicAccounts != null) {
            client_trans_id = oldElectronicAccounts.getClientTransId();
            JSONObject registerStatus = getRegisterStatus(client_trans_id);
            if (registerStatus.getString("result").equals("AUDITING")) {
                throw new XkdException("机构注册中");
            } else if (registerStatus.getString("result").equals("SUCCESS")) {
                throw new XkdException("机构申请成功");
            }
        } else {
            client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        }
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2601";


        Map<String, Object> dataMap = new HashMap<>();

        dataMap.put("account_no", company.getBankAccount());
        dataMap.put("settle_id", company.getInterbankAccount());
        dataMap.put("org_name", company.getCompanyName());
        dataMap.put("email", company.getCompanyEmail());
        dataMap.put("legal_name", company.getLegalEntityName());

        if (registerDto.getLegalIdType().equals(SysConstant.LEGAL_ID_TYPE_ZERO)) {
            dataMap.put("legal_idcard", company.getCorporateIdCard());
        } else {
            dataMap.put("legal_idcard", registerDto.getLegalIdcard());
        }

        dataMap.put("legal_idcard_start_expired", DateUtil.format(registerDto.getLegalIdcardStartExpired(), "yyyy-MM-dd"));
        dataMap.put("legal_idcard_expired", DateUtil.format(registerDto.getLegalIdcardExpired(), "yyyy-MM-dd"));
        dataMap.put("legal_mobile", AESUtil.decrypt(company.getLegalEntityPhone(), aesKey));
        dataMap.put("business_name", registerDto.getBusinessName());
        dataMap.put("business_idcard", registerDto.getBusinessIdcard());
        dataMap.put("business_idcard_expired", DateUtil.format(registerDto.getBusinessIdcardExpired(), "yyyy-MM-dd"));
        dataMap.put("business_mobile", AESUtil.decrypt(registerDto.getBusinessMobile(), aesKey));
        dataMap.put("business_license_no", company.getUnifiedSocialCreditCode());

        dataMap.put("business_license_start_expired", DateUtil.format(company.getBusinessLicenseStartExpired(), "yyyy-MM-dd"));
        dataMap.put("business_license_expired", DateUtil.format(company.getBusinessLicenseExpired(), "yyyy-MM-dd"));
        dataMap.put("address", company.getLocationOfEnterprise());
        dataMap.put("registered_capital", company.getRegisteredCapital());
        dataMap.put("file_no", registerDto.getFileNo());
        dataMap.put("business_scope", company.getBusinessType());

        dataMap.put("province", registerDto.getProvinceName());
        dataMap.put("city", registerDto.getCityName());
        dataMap.put("country", registerDto.getCountryName());
        dataMap.put("street", registerDto.getStreet());
        dataMap.put("site_name", "无网站");
        dataMap.put("web_site", "无");
        dataMap.put("open_type", "email");


        List beneficiaryList = new ArrayList();
        List<BeneficiaryElectronic> list = registerDto.getBeneficiaryElectronics();
        list.forEach(b -> {
            //  控股股东信息
            Map<String, Object> shareholder = new HashMap();
            shareholder.put("type", b.getType());
            shareholder.put("beneficiary_name", b.getBeneficiaryName());
            shareholder.put("beneficiary_id_type", b.getBeneficiaryIdType());
            shareholder.put("beneficiary_id_no", b.getBeneficiaryIdNo());
            shareholder.put("beneficiary_id_effDate", DateUtil.format(b.getBeneficiaryIdEffDate(), "yyyy-MM-dd"));
            shareholder.put("beneficiary_id_offDate", DateUtil.format(b.getBeneficiaryIdOffDate(), "yyyy-MM-dd"));
            shareholder.put("beneficiary_phone", AESUtil.decrypt(b.getBeneficiaryPhone(), aesKey));
            shareholder.put("beneficiary_address", b.getBeneficiaryAddress());
            String data = JSONObject.fromObject(shareholder).toString();
            beneficiaryList.add(data);
        });

        log.info("受益人/控股股东信息:" + beneficiaryList);
        dataMap.put("beneficiary_items", beneficiaryList);

        dataMap.put("icp_code", "无备案号");
        dataMap.put("bank_type", "HT");

        String reg_province = provincesInfoMapper.selectById(company.getProvince()).getCityName();
        String reg_city = provincesInfoMapper.selectById(company.getCity()).getCityName();
        String reg_country = provincesInfoMapper.selectById(company.getCounty()).getCityName();

        dataMap.put("reg_province", reg_province);
        dataMap.put("reg_city", reg_city);
        dataMap.put("reg_country", reg_country);
        dataMap.put("org_type", company.getTypeOfEnterprise());
        dataMap.put("org_size", registerDto.getOrgSize());
        dataMap.put("org_economy", registerDto.getOrgEconomy());
        dataMap.put("org_industry", registerDto.getOrgIndustry());
        dataMap.put("org_listing", registerDto.getOrgListing());

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);


        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", backUrl);
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));
        log.info("data-->" + Signer.Base64Encode(data));
        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("机构注册接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果" + bool);
        String result = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果" + result);
        log.info("业务返回内容" + mapResult.get("resp_msg"));
        JSONObject jsonObject = JSONObject.fromObject(result);
        if (!jsonObject.getString("status").equals("SUCCESS"))
            throw new XkdException("机构注册申请失败:" + jsonObject.getString("errorMsg"));

        //插入本次申请信息
        ElectronicAccounts electronicAccounts = new ElectronicAccounts();
        BeanUtils.copyProperties(registerDto, electronicAccounts);
        electronicAccounts.setClientTransId(client_trans_id);
        List<BeneficiaryElectronic> beneficiaryElectronics = registerDto.getBeneficiaryElectronics();
        if (oldElectronicAccounts != null) {
            electronicAccountsMapper.updateById(electronicAccounts);
            beneficiaryElectronicMapper.delete(new LambdaQueryWrapper<BeneficiaryElectronic>().eq(BeneficiaryElectronic::getElectronicId, electronicAccounts.getId()));
        } else {
            electronicAccountsMapper.insert(electronicAccounts);
        }
        beneficiaryElectronics.forEach(b -> {
            b.setElectronicId(electronicAccounts.getId());
        });
        beneficiaryElectronicMapper.insertBatch(beneficiaryElectronics);
        return jsonObject.getString("wallet_no");
    }

    public File multipartFileToFile(MultipartFile file, Integer companyId) throws Exception {
        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            String fileName = companyId + "YCKZH" + file.getOriginalFilename();
            String path = localPathDir + registerAccount;
            File dirFile = new File(path);
            if (!dirFile.exists()) {
                dirFile.mkdirs();
            }
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(path + "/" + fileName);
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;

    }

    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            throw new RuntimeException("读取文件错误", e);
        }

    }

    @Override
    public BalanceVo balance(String walletNo, String type) throws IOException {
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2204";

        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("wallet_no", walletNo);
        dataMap.put("type", type);
        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", "");
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("余额查询调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
//        int balance = jsonObject.getInt("balance");
        int balance = jsonObject.optInt("balance", 0);
        BalanceVo balanceVo = new BalanceVo();
        if (!loans_out_no.equals(walletNo)) {
            balanceVo = companyMapper.selectAmount(walletNo);
        }
        if (type.equals("1")) {
            int frozenAmount = jsonObject.optInt("frozenAmount", 0);
            int availAmount = jsonObject.optInt("availAmount", 0);
            balanceVo.setFrozenAmount(new BigDecimal(frozenAmount).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
            balanceVo.setAvailAmount(new BigDecimal(availAmount).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
        }
        balanceVo.setBalance(new BigDecimal(balance).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));

        return balanceVo;
    }

    public static void main(String[] args) {
//        DateTime dateTime = DateUtil.parse("20250430151957", "yyyy-MM-dd HH:mm:ss");
        DateTime dateTime = DateUtil.parse("20250430151957", "yyyyMMddHHmmss");
        String da = String.valueOf(dateTime);
        System.out.println(dateTime);
    }

    //创建转账订单
    public HashMap<String, String> createTransferOrder(TransferAccountsDto transferAccountsDto, Integer companyId) throws IOException {
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2503";
        List transferAccountsDtos = new ArrayList();
        Map<String, Object> dataMap = new HashMap<>();

        Map<String, Object> order = new HashMap<>();
        String orderCode = OrderNumUtil.getTransferOrder();
        long amount = transferAccountsDto.getAmount();
        String payeeWalletNo = transferAccountsDto.getPayeeWalletNo();
        String payerWalletNo = transferAccountsDto.getPayerWalletNo();
        order.put("order_no", orderCode);
        order.put("index", transferAccountsDto.getIndex());
        order.put("payee_wallet_no", payeeWalletNo);
        order.put("payer_wallet_no", payerWalletNo);
        order.put("trans_time", trans_timestamp);
        order.put("amount", String.valueOf(amount));
        order.put("order_desc", transferAccountsDto.getOrderDesc());
        order.put("bank_type", "HT");
        String orderData = JSONObject.fromObject(order).toString();
        transferAccountsDtos.add(orderData);

        dataMap.put("order_param", transferAccountsDtos);

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", transferOrderReturn);
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("创建转账订单接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);

        JSONObject jsonObject = JSONObject.fromObject(s);
        if (jsonObject.getString("status").equals("FAIL")) {
            throw new XkdException("创建转账订单失败:" + jsonObject.getString("memo"));
        }
        /*
         * 插入电子转账信息
         * */
        ElectronicTransferInfo electronicTransferInfo = new ElectronicTransferInfo();
        electronicTransferInfo.setCompanyId(companyId);
        electronicTransferInfo.setPayeeWalletNo(payeeWalletNo);
        electronicTransferInfo.setPayerWalletNo(payerWalletNo);
        electronicTransferInfo.setOrderNo(orderCode);
        electronicTransferInfo.setAmount(amount);
        electronicTransferInfo.setOrderDesc(transferAccountsDto.getOrderDesc());
        electronicTransferInfo.setType(transferAccountsDto.getType());
        electronicTransferInfo.setRemark(transferAccountsDto.getRemark());
        electronicTransferInfo.setTransTime(String.valueOf(DateUtil.parse(trans_timestamp, "yyyyMMddHHmmss")));
        electronicTransferInfo.setClientTransId(client_trans_id);
        electronicTransferInfo.setRemainingAmount(amount);
        electronicTransferInfoMapper.insert(electronicTransferInfo);
        HashMap<String, String> map = new HashMap<>();
        map.put("status", jsonObject.getString("status"));
        map.put("memo", jsonObject.getString("memo"));
        return map;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public HashMap<String, String> transferAccounts(TransferDto transferDto) {
        Integer companyId = transferDto.getCompanyId();
        String type = transferDto.getType();
        if (type == null)
            throw new XkdException("请选择转账类型");
        if (!type.equals(SysConstant.ELECTRONIC_TRANSFER_ONE) && !type.equals(SysConstant.ELECTRONIC_TRANSFER_TOW))
            throw new XkdException("type类型错误");

        //判断余额是否充足
        //保证每次一个线程查询
        RLock lock = redissonClient.getLock(transferOrderLock + companyId);
        try {
            log.info("尝试获取锁: {}", transferOrderLock + companyId);
            lock.lock();
            log.info("成功获取锁: {}", transferOrderLock + companyId);
            CompanyAccount companyAccount = companyAccountMapper.selectById(companyId);
            if (type.equals(SysConstant.ELECTRONIC_TRANSFER_ONE)) {
                BalanceVo balance = balance(companyAccount.getPrestoreNo(), "1");
                if (balance.getBalance().multiply(new BigDecimal(100)).intValue() < transferDto.getAmount())
                    throw new XkdException("企业电子账户余额不足");
            } else {
                Company company = companyMapper.selectById(companyId);
                long i = company.getOutBalance() - company.getOutBalanceFreeze();//放款账户余额减去冻结金额=可用金额
                if (i < transferDto.getAmount())
                    throw new XkdException("放款账户可用余额不足");
                //冻结放款账户余额
                companyMapper.updateOutAmountFreeze(companyId, transferDto.getAmount());
            }
            TransferAccountsDto transferAccountsDto = new TransferAccountsDto();
            String desc = "";
            if (type.equals(SysConstant.ELECTRONIC_TRANSFER_ONE)) {
                transferAccountsDto.setPayeeWalletNo(loans_out_no);
                transferAccountsDto.setPayerWalletNo(companyAccount.getPrestoreNo());
                desc = "充值";
            } else {
                transferAccountsDto.setPayeeWalletNo(companyAccount.getPrestoreNo());
                transferAccountsDto.setPayerWalletNo(loans_out_no);
                desc = "退款";
            }
            transferAccountsDto.setIndex("1");
            transferAccountsDto.setType(type);
            transferAccountsDto.setOrderDesc(desc);
            transferAccountsDto.setAmount(transferDto.getAmount());
            transferAccountsDto.setRemark(transferDto.getRemark());
            return createTransferOrder(transferAccountsDto, companyId);

        } catch (XkdException e) {
            throw e; // 直接抛出业务异常
        } catch (Exception e) {
            throw new RuntimeException("系统异常", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("释放锁: {}", transferOrderLock + companyId);
            }
        }
    }


    @Override
    public JSONObject getRegisterStatus(String origClientTransId) throws IOException {
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2604";

        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("orig_client_trans_id", origClientTransId);

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", "");
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);

//        return jsonObject.getString("audit_info");
        return jsonObject;

    }

    @Override
    public String getAccountStatus(String walletNo) throws IOException {
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2603";

        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("wallet_no", walletNo);
        dataMap.put("bank_type", "HT");

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", "");
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        return jsonObject.getString("account_status");
    }

    @Override
    //提现到对公账户
//    public void withdrawDeposit(PrestoreWithdrawDepositDto prestoreWithdrawDepositDto) throws IOException {
    public void withdrawDeposit(String allot_client_trans_id) throws IOException {
//        BindBank bindBank = bindBankMapper.selectById(prestoreWithdrawDepositDto.getId());
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2212";

        OfflineTransferInfo allot = offlineTransferInfoMapper.selectOne(new LambdaQueryWrapper<OfflineTransferInfo>().eq(OfflineTransferInfo::getAllotClientTransId, allot_client_trans_id));
        Integer companyId = allot.getCompanyId();
        CompanyAccount companyAccount = companyAccountMapper.selectById(companyId);
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("wallet_no", companyAccount.getPrestoreNo());
        dataMap.put("card_no", allot.getPeerAccNo());
        dataMap.put("card_name", allot.getPeerAccName());
        dataMap.put("order_amount", String.valueOf(allot.getAmount()));
        dataMap.put("settle_id", allot.getPeerBankNo());

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", withdrawDepositReturn);
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("提现接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        if (jsonObject.getString("status").equals("FAIL"))
            throw new XkdException("提现受理失败:" + jsonObject.getString("status_msg"));
        //受理成功 入库
        OfflineTransferInfo offlineTransferInfo = new OfflineTransferInfo();
        offlineTransferInfo.setClientTransId(client_trans_id);
        LambdaQueryWrapper<OfflineTransferInfo> lqw = new LambdaQueryWrapper<>();
        lqw.eq(OfflineTransferInfo::getAllotClientTransId, allot_client_trans_id);
        offlineTransferInfoMapper.update(offlineTransferInfo, lqw);
    }

    @Override
    public HashMap<String, String> getTransferOrder(String clientTransId) throws IOException {
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2502";
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("orig_client_trans_id", clientTransId);

        String data = JSONObject.fromObject(dataMap).toString();
        System.out.println("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", "");
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm("https://v-rzt.mandao-tech.com/api/trade", requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        HashMap<String, String> map = new HashMap<>();
        map.put("status", jsonObject.getString("status"));
        map.put("memo", jsonObject.getString("memo"));
        return map;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void getTransferOrderReturn(String app_id,
                                       String sign_type,
                                       String client_trans_id,
                                       String trans_timestamp,
                                       String trans_type,
                                       String callback_url,
                                       String version,
                                       String data,
                                       String sign) throws Exception {

        //验签
        JSONObject jsonObject = getData(app_id, sign_type, client_trans_id, trans_timestamp, trans_type, callback_url, version, data, sign);

        String status = jsonObject.getString("status");
        String tradeNo = jsonObject.getString("trade_no");
//        ElectronicTransferInfo electronicTransferInfo = electronicTransferInfoMapper.selectById(tradeNo);
        ElectronicTransferInfo electronicTransferInfo = null;
        for (int i = 0; i < 10; i++) {
            electronicTransferInfo = electronicTransferInfoMapper.selectById(tradeNo);
            log.info("第{}次尝试获取转账订单：{}", i + 1, electronicTransferInfo);
            if (electronicTransferInfo == null) {
                Thread.sleep(500);
            } else {
                break;
            }
        }
        if (electronicTransferInfo.getStatus().equals(SysConstant.CREATE_ORDER_STATUS_ONE)) {//支付中的订单才处理  以免重复处理
            log.info("处理订单回调------------------");
            if (status.equals("SUCCESS")) {
                if (electronicTransferInfo.getType().equals(SysConstant.ELECTRONIC_TRANSFER_ONE)) {
                    //如果是预存款到放款账户
                    //增加公司放款账户余额
                    companyMapper.updateOutAmount(electronicTransferInfo.getCompanyId(), electronicTransferInfo.getAmount());
                } else if (electronicTransferInfo.getType().equals(SysConstant.ELECTRONIC_TRANSFER_TOW)) {
                    //如果是放款账户到预存款账户
                    //扣减公司放款账户余额以及冻结金额
                    log.info("放款到预存款------------------");
                    companyMapper.updateOutAmount(electronicTransferInfo.getCompanyId(), -electronicTransferInfo.getAmount());
                    companyMapper.updateOutAmountFreeze(electronicTransferInfo.getCompanyId(), -electronicTransferInfo.getAmount());
                }
                status = SysConstant.CREATE_ORDER_STATUS_THREE;
            } else if (status.equals("FAIL")) {
                if (electronicTransferInfo.getType().equals(SysConstant.ELECTRONIC_TRANSFER_TOW)) {
                    //如果是放款账户到预存款账户
                    //扣减冻结金额
                    companyMapper.updateOutAmountFreeze(electronicTransferInfo.getCompanyId(), -electronicTransferInfo.getAmount());
                }
                status = SysConstant.CREATE_ORDER_STATUS_TOW;
            }
            electronicTransferInfoMapper.update(status, tradeNo);
        }

    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void HTRevenueAccountReturn(String app_id,
                                       String sign_type,
                                       String client_trans_id,
                                       String trans_timestamp,
                                       String trans_type,
                                       String callback_url,
                                       String version,
                                       String data,
                                       String sign) throws Exception {

        //验签
        JSONObject jsonObject = getData(app_id, sign_type, client_trans_id, trans_timestamp, trans_type, callback_url, version, data, sign);

        String amount = jsonObject.getString("amount");
        String peerAccNo = jsonObject.getString("peer_acc_no");
        String peerAccName = jsonObject.getString("peer_acc_name");
        String recordTime = jsonObject.getString("record_time");
        String remark = jsonObject.getString("remark");
        String peerBankNo = jsonObject.getString("peer_bank_no");
        String peerBankName = jsonObject.getString("peer_bank_name");
        String acctId = jsonObject.getString("acct_id");

        Integer companyId = companyAccountMapper.selectOne(new LambdaQueryWrapper<CompanyAccount>().eq(CompanyAccount::getPrestoreBankAccount, acctId)).getCompanyId();
        OfflineTransferInfo offlineTransferInfo = new OfflineTransferInfo();
        offlineTransferInfo.setCompanyId(companyId);
        offlineTransferInfo.setAmount(Long.valueOf(amount));
        offlineTransferInfo.setRemark(remark);
        offlineTransferInfo.setPeerAccNo(peerAccNo);
        offlineTransferInfo.setPeerAccName(peerAccName);
        offlineTransferInfo.setRecordTime(DateUtil.parse(recordTime));
        offlineTransferInfo.setPeerBankNo(peerBankNo);
        offlineTransferInfo.setPeerBankName(peerBankName);
        offlineTransferInfo.setAcctId(acctId);
        offlineTransferInfo.setClientTransId(client_trans_id);
        offlineTransferInfo.setWithdrawDepositType("1");
        offlineTransferInfo.setType(SysConstant.OFFLINE_TRANSFER_ONE);
        offlineTransferInfo.setStatus(SysConstant.CREATE_ORDER_STATUS_THREE);
        offlineTransferInfoMapper.insert(offlineTransferInfo);
        //收取入金服务费
        iCompanyService.deductingBalanceMain(null, null, null, null, SysConstant.BUSINESS_FEE_SIX, companyId, amount, client_trans_id);
        //修改入金累计金额
        companyMapper.updateRechargeAmount(companyId, amount);

    }


    @Override
    public void withdrawDepositReturn(String app_id,
                                      String sign_type,
                                      String client_trans_id,
                                      String trans_timestamp,
                                      String trans_type,
                                      String callback_url,
                                      String version,
                                      String data,
                                      String sign) throws Exception {

        //验签
        JSONObject jsonObject = getData(app_id, sign_type, client_trans_id, trans_timestamp, trans_type, callback_url, version, data, sign);
        String status = jsonObject.getString("status");
        String statusMsg = jsonObject.getString("status_msg");
        if ("null".equals(statusMsg) || statusMsg == null || "".equals(statusMsg.trim())) {
            statusMsg = null; // 设置默认值为空字符串或其他默认提示
        }
        if (status.equals("SUCCESS")) {
            status = SysConstant.CREATE_ORDER_STATUS_THREE;
            OfflineTransferInfo offlineTransferInfo = offlineTransferInfoMapper.selectOne(new LambdaQueryWrapper<OfflineTransferInfo>().eq(OfflineTransferInfo::getClientTransId, client_trans_id));
            iCompanyService.deductingBalanceMain(null, null, null, null, SysConstant.BUSINESS_FEE_EIGHT, offlineTransferInfo.getCompanyId(), offlineTransferInfo.getAmount()+"", client_trans_id);
        } else if (status.equals("FAIL")) {
            status = SysConstant.CREATE_ORDER_STATUS_TOW;
        }
        offlineTransferInfoMapper.updateStatus(status, client_trans_id, statusMsg);
    }


    @Override
    public void bindBankCard(BindBank bindBank) throws IOException {
        BindBank oldBank = bindBankMapper.selectOne(new LambdaQueryWrapper<BindBank>().eq(BindBank::getAccNo, bindBank.getAccNo()));
        if (oldBank != null)
            throw new XkdException("卡号已绑定");

        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2120";

        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("wallet_no", bindBank.getWalletNo());
        dataMap.put("acc_no", bindBank.getAccNo());
        dataMap.put("acc_name", bindBank.getAccName());
        dataMap.put("bank_code", bindBank.getBankCode());
        dataMap.put("bank_name", bindBank.getBankName());
        dataMap.put("remark", bindBank.getRemark());

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", "");
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("企业绑卡接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        if (jsonObject.getString("status").equals("FAIL"))
            throw new XkdException(jsonObject.getString("memo"));
        //插入绑卡信息
        bindBankMapper.insert(bindBank);
    }

    //放款前调拨提现
    @Override
    public void outAmountAllot(Integer companyId, String wallet_no, String order_amount, String client_trans_id) throws IOException {
        log.info("执行放款调拨提现");
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2206";
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("wallet_no", wallet_no);
        dataMap.put("order_amount", order_amount);

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", outAmountAllotReturn);
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));
        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("调拨提现接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        if (jsonObject.getString("status").equals("FAIL"))
            throw new XkdException("受理失败:" + jsonObject.getString("status_msg"));
        //修改放款账户冻结金额
        companyMapper.updateOutAmountFreeze(companyId, Long.valueOf(order_amount));
        log.info("放款调拨提现执行完毕");
    }

    @Override
    public void allot(PrestoreWithdrawDepositDto prestoreWithdrawDepositDto) throws IOException {
        BindBank bindBank = bindBankMapper.selectById(prestoreWithdrawDepositDto.getId());
        Integer companyId = bindBank.getCompanyId();
        String lockName = SysConstant.FEE_LOCK + companyId;
        RLock lock = redissonClient.getLock(lockName);
        try {
            log.info("尝试获取锁: {}", lockName);
            lock.lock();
            log.info("成功获取锁: {}", lockName);
            dlApiService.checkBalanceAndFreeze(companyId);
        } catch (Exception e) {
            throw new XkdException(e.getMessage());
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("当前线程: {} 释放锁: {}", Thread.currentThread().getName(), lockName);
            }
        }
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2206";
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("wallet_no", bindBank.getWalletNo());
        dataMap.put("order_amount", String.valueOf(prestoreWithdrawDepositDto.getOrderAmount()));

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", allotReturn);
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("调拨提现接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        if (jsonObject.getString("status").equals("FAIL"))
            throw new XkdException("受理失败:" + jsonObject.getString("status_msg"));
        //受理成功 入库
        OfflineTransferInfo offlineTransferInfo = new OfflineTransferInfo();
        offlineTransferInfo.setCompanyId(companyId);
        offlineTransferInfo.setAmount(prestoreWithdrawDepositDto.getOrderAmount());
        offlineTransferInfo.setPeerAccNo(bindBank.getAccNo());
        offlineTransferInfo.setPeerAccName(bindBank.getAccName());
        offlineTransferInfo.setPeerBankNo(bindBank.getBankCode());
        offlineTransferInfo.setRecordTime(new Date());
        offlineTransferInfo.setPeerBankName(bindBank.getBankName());
        offlineTransferInfo.setWithdrawDepositType("1");
        offlineTransferInfo.setType(SysConstant.OFFLINE_TRANSFER_TOW);
        offlineTransferInfo.setStatus(SysConstant.CREATE_ORDER_STATUS_ONE);
        offlineTransferInfo.setAllotClientTransId(client_trans_id);
        offlineTransferInfoMapper.insert(offlineTransferInfo);
    }

    @Override
    public void allotReturn(String app_id,
                            String sign_type,
                            String client_trans_id,
                            String trans_timestamp,
                            String trans_type,
                            String callback_url,
                            String version,
                            String data,
                            String sign) throws Exception {
        //验签
        JSONObject jsonObject = getData(app_id, sign_type, client_trans_id, trans_timestamp, trans_type, callback_url, version, data, sign);
        String status = jsonObject.getString("status");
        String statusMsg = jsonObject.getString("status_msg");
        if ("null".equals(statusMsg) || statusMsg == null || "".equals(statusMsg.trim())) {
            statusMsg = null; // 设置默认值为空字符串或其他默认提示
        }
        if (status.equals("SUCCESS")) {
            log.info("调拨提现成功");
            //调用提现
            withdrawDeposit(client_trans_id);
        } else if (status.equals("FAIL")) {
            log.info("调拨提现失败：{}", statusMsg);
            offlineTransferInfoMapper.updateAllotStatus(client_trans_id, statusMsg);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void outAmountAllotReturn(String app_id, String sign_type, String client_trans_id, String trans_timestamp, String trans_type, String callback_url, String version, String data, String sign) throws Exception {
        log.info("执行放款调拨提现回调函数");
        //验签
        JSONObject jsonObject = getData(app_id, sign_type, client_trans_id, trans_timestamp, trans_type, callback_url, version, data, sign);
        String status = jsonObject.getString("status");
        String statusMsg = jsonObject.getString("status_msg");
        if ("null".equals(statusMsg) || statusMsg == null || "".equals(statusMsg.trim())) {
            statusMsg = null; // 设置默认值为空字符串或其他默认提示
        }
        OutOrderInfo outOrderInfo = null;
        for (int i = 1; i <= maxRetry; i++) {
            outOrderInfo = outOrderInfoMapper.selectOne(new LambdaQueryWrapper<OutOrderInfo>().eq(OutOrderInfo::getClientTransId, client_trans_id));
            log.info("第 {} 次查询放款数据：{}", i, outOrderInfo);
            if (outOrderInfo != null)
                break;
            try {
                Thread.sleep(sleepMillis);
            } catch (InterruptedException e) {
                log.warn("等待过程中被中断", e);
                Thread.currentThread().interrupt(); // 恢复中断状态
                break;
            }
        }
        if (outOrderInfo == null) {
            log.error("重试 {} 次后仍未获取到合同数据", maxRetry);
            throw new RuntimeException("未获取到合同数据，请稍后再试");
        }
        long i = outOrderInfo.getAmount();
        if (status.equals("SUCCESS")) {
            log.info("放款调拨提现成功");
            //调用放款接口
            OutAmountDto outAmountDto = new OutAmountDto();
            outAmountDto.setOrder(outOrderInfo.getOrderNo());
            BigDecimal divide = new BigDecimal(outOrderInfo.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
            outAmountDto.setTransMoney(divide + "");
            outAmountDto.setToAccName(outOrderInfo.getToAccName());
            outAmountDto.setToAccNo(outOrderInfo.getToAccNo());
            outAmountDto.setToBankName(outOrderInfo.getToBankName());
            outAmountDto.setTransCardId(outOrderInfo.getTransCardId());
            outAmountDto.setIncomingId(outOrderInfo.getIncomingId());
            outAmountDto.setId(outOrderInfo.getOrderId());
            outAmountDto.setTransCnap(outOrderInfo.getTransCnap());
            outAmountDto.setChannelType(SysConstant.CHANNEL_TYPE_ONE);
            //修改公司放款余额 和 宝付余额
            companyMapper.updateOutAndBaofuBalance(outOrderInfo.getCompanyId(), i);
            //调用放款接口
            dlApiService.outAmount(outAmountDto);
        } else if (status.equals("FAIL")) {
            log.info("放款调拨提现失败：{}", statusMsg);
            String outStatus = "3";
            String payStatus = "3";
            OutInfo outInfo = new OutInfo();
            outInfo.setOutStatus(outStatus);
            LambdaQueryWrapper<OutInfo> lqw = new LambdaQueryWrapper<>();
            lqw.eq(OutInfo::getOutId, outOrderInfo.getOrderId());
            //修改放款状态
            outInfoMapper.update(outInfo, lqw);
            OutOrderInfo o = new OutOrderInfo();
            //修改放款订单状态
            o.setPayStatus(payStatus);
            o.setFailReason(statusMsg);
            LambdaQueryWrapper<OutOrderInfo> lqw2 = new LambdaQueryWrapper<>();
            lqw2.eq(OutOrderInfo::getOrderNo, outOrderInfo.getOrderNo());
            outOrderInfoMapper.update(o, lqw2);
        }
        //修改冻结金额
        companyMapper.updateOutAmountFreeze(outOrderInfo.getCompanyId(), -i);
        log.info("放款调拨提现回调函数执行完毕");
    }

    @Override
    public void baofuwithdrawDeposit(PrestoreWithdrawDepositDto prestoreWithdrawDepositDto) throws IOException {
        BindBank bindBank = bindBankMapper.selectById(prestoreWithdrawDepositDto.getId());
        String lockName = SysConstant.FEE_LOCK + bindBank.getCompanyId();
        RLock lock = redissonClient.getLock(lockName);
        try {
            log.info("尝试获取锁: {}", lockName);
            lock.lock();
            log.info("成功获取锁: {}", lockName);
         dlApiService.checkBalanceAndFreeze(bindBank.getCompanyId());
        } catch (Exception e) {
            throw new XkdException(e.getMessage());
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("当前线程: {} 释放锁: {}", Thread.currentThread().getName(), lockName);
            }
        }
        String client_trans_id = "T" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        String trans_timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
        String trans_type = "2212";

        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("wallet_no", bindBank.getWalletNo());
        dataMap.put("card_no", bindBank.getAccNo());
        dataMap.put("card_name", bindBank.getAccName());
        dataMap.put("order_amount", String.valueOf(prestoreWithdrawDepositDto.getOrderAmount()));
        dataMap.put("settle_id", bindBank.getBankCode());

        String data = JSONObject.fromObject(dataMap).toString();
        log.info("业务参数:" + data);

        String sign;
        TreeMap<String, String> postParam = new TreeMap<String, String>();
        postParam.put("app_id", APPID);
        postParam.put("sign_type", SIGNTYPE);
        postParam.put("client_trans_id", client_trans_id);
        postParam.put("trans_timestamp", trans_timestamp);
        postParam.put("trans_type", trans_type);
        postParam.put("callback_url", withdrawDepositReturn);
        postParam.put("version", VERSION);
        postParam.put("data", Signer.Base64Encode(data));

        String reqSignStr = Signer.concatTreeMapParam(postParam);
        log.info("待签名字符:" + reqSignStr);
        sign = Signer.sign(reqSignStr, pfxPath, pfxPathPassword);
        log.info("签名结果:" + sign);
        postParam.put("sign", sign);
        JSONObject requestData = JSONObject.fromObject(postParam);
        log.info("请求参数：" + requestData);
        String results = HttpUtil.RequestForm(baseUrl, requestData);
        log.info("响应结果：" + results);
        TreeMap<String, String> mapResult = JXMConvertUtil.JsonConvertHashMap(results);// 将响应结果转化为TreeMap对象。
        if (!"00000000".equals(mapResult.get("resp_code")))
            throw new XkdException("提现接口调用失败" + mapResult.get("resp_msg"));
        sign = mapResult.get("sign");
        mapResult.remove("sign");
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：" + signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果:" + bool);
        String s = Signer.Base64Decode(mapResult.get("data"));
        log.info("业务响应结果:" + s);
        JSONObject jsonObject = JSONObject.fromObject(s);
        if (jsonObject.getString("status").equals("FAIL"))
            throw new XkdException("提现受理失败:" + jsonObject.getString("status_msg"));
        //受理成功 入库
        OfflineTransferInfo offlineTransferInfo = new OfflineTransferInfo();
        offlineTransferInfo.setCompanyId(bindBank.getCompanyId());
        offlineTransferInfo.setAmount(prestoreWithdrawDepositDto.getOrderAmount());
        offlineTransferInfo.setPeerAccNo(bindBank.getAccNo());
        offlineTransferInfo.setPeerAccName(bindBank.getAccName());
        offlineTransferInfo.setPeerBankNo(bindBank.getBankCode());
        offlineTransferInfo.setPeerBankName(bindBank.getBankName());
        offlineTransferInfo.setRecordTime(new Date());
        offlineTransferInfo.setType(SysConstant.OFFLINE_TRANSFER_TOW);
        offlineTransferInfo.setStatus(SysConstant.CREATE_ORDER_STATUS_ONE);
        offlineTransferInfo.setClientTransId(client_trans_id);
        offlineTransferInfoMapper.insert(offlineTransferInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void towRecharge(TowRechargeDto towRechargeDto) throws Exception {
        Integer companyId = towRechargeDto.getCompanyId();
        String lockName = towBaofuwithdrawLock + companyId;
        RLock lock = redissonClient.getLock(lockName);
        try {
            log.info("尝试获取锁: {}", lockName);
            boolean b = lock.tryLock(10, TimeUnit.MILLISECONDS);
            if (!b) {
                log.info("获取锁失败: {}", lockName);
                throw new Exception("服务器繁忙！");
            }
            log.info("成功获取锁: {}", lockName);
            //查询未分配余额
            BalanceVo balanceVo = dlApiService.baofuBalance(SysConstant.CHANNEL_TYPE_TWO);//查询宝付总余额
            BigDecimal totalBalance = companyMapper.getTotalBaofuBalance();//已分配金额
            BigDecimal subtract = balanceVo.getBalance().subtract(totalBalance);//可分配金额
            BigDecimal divide = towRechargeDto.getAmount().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);//本次充值金额
            if (subtract.compareTo(divide) < 0)
                throw new XkdException("可分配金额不足");
            ChannelTowRecharge channelTowRecharge = new ChannelTowRecharge();
            channelTowRecharge.setCompanyId(companyId);
            channelTowRecharge.setAmount(divide);
            channelTowRecharge.setVoucher(towRechargeDto.getVoucher());
            channelTowRecharge.setCreateTime(new Date());
            channelTowRecharge.setRemark(towRechargeDto.getRemark());
            if (StringUtils.isNotBlank(channelTowRecharge.getVoucher())) {
                channelTowRecharge.setTradeTime(new Date());
            }
            channelTowRechargeMapper.insert(channelTowRecharge);
            /*
             * 插入电子转账信息
             * */
            companyMapper.towRecharge(towRechargeDto);
            //收取入金 服务费
            iCompanyService.deductingBalanceMain(null, null, null, null, SysConstant.BUSINESS_FEE_SIX, companyId, String.valueOf(towRechargeDto.getAmount()), null);
        } catch (Exception e) {
            log.error("渠道二充值，请求参数: {}, 锁键: {}, 异常信息: {}", towRechargeDto, lockName, e.getMessage(), e);
            throw e;
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("渠道二充值任务释放锁，锁键: {}", lockName);
            }
        }

    }

    @Override
    public TowBalanceVo towBalance(TowBalanceDto towBalanceDto) {
        Company company = companyMapper.selectById(towBalanceDto.getCompanyId());
        TowBalanceVo towBalanceVo = new TowBalanceVo();
        if (towBalanceDto.getType().equals("1")) {//放款账户
            towBalanceVo.setTowBaofuBalance(new BigDecimal(company.getTowBaofuBalance()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
            towBalanceVo.setTowOutBalanceFreeze(new BigDecimal(company.getTowOutBalanceFreeze()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
        } else {
            towBalanceVo.setTowReturnBalance(new BigDecimal(company.getTowReturnBalance()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
            towBalanceVo.setTowReturnBalanceFreeze(new BigDecimal(company.getTowReturnBalanceFreeze()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
            towBalanceVo.setTowReturnAmount(new BigDecimal(company.getTowReturnAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
        }
        return towBalanceVo;
    }

    @Override
    public TowBalanceVo PTtowBalance() {
        TowBalanceVo towBalanceVo = companyMapper.PTtowBalance();
        BigDecimal allotAmount = channelPayTowMapper.getAllotAmount();
        towBalanceVo.setAllotAmount(allotAmount);
        return towBalanceVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void refuseCertification(com.alibaba.fastjson.JSONObject json) {
        com.alibaba.fastjson.JSONObject body = getCertificationData(json);

        String thirdPartyOrderId = body.getString("thirdPartyOrderId");//商户订单
        String reason = body.getString("reason");//拒绝原因
        CertificationOrder certificationOrder = certificationOrderMapper.selectOne(new LambdaQueryWrapper<CertificationOrder>().eq(CertificationOrder::getOrderNo, thirdPartyOrderId));
        if (!certificationOrder.getStatus().equals("0"))
            throw new XkdException("该订单已处理");
        certificationOrderMapper.refuseCertification(thirdPartyOrderId, reason);
        certificationMapper.refuseCertification(certificationOrder.getCertificationId(), reason);
        //删除创建的合同(为了重新申请公证)
        List<String> removeContracts = contractMapper.selectRemoveContracts(certificationOrder.getOutId());
        LambdaQueryWrapper<Contract> lqw = new LambdaQueryWrapper<>();
        ArrayList<String> list = new ArrayList<>();
        list.add(SysConstant.CONTRACT_TYPE_TOW);
        list.add(SysConstant.CONTRACT_TYPE_THREE);
        list.add(SysConstant.CONTRACT_TYPE_FIVE);
        list.add(SysConstant.CONTRACT_TYPE_SIX);
        list.add(SysConstant.CONTRACT_TYPE_SEVEN);
        lqw.eq(Contract::getOutId, certificationOrder.getOutId()).in(Contract::getType, list);
        contractMapper.delete(lqw);
        fileService.filesRemove(removeContracts);

    }

    @Override
    public void acceptContractNotifyUrl(com.alibaba.fastjson.JSONObject json) {
        com.alibaba.fastjson.JSONObject body = getCertificationData(json);
        String thirdPartyOrderId = body.getString("thirdPartyOrderId");//商户订单
        String type = body.getString("type");//合同类型
        String base64 = body.getString("base64");//文件base64
        String contractType = "";
        if (type.equals("1020")) {//贷款合同
            contractType = SysConstant.CONTRACT_TYPE_TOW;
        } else if (type.equals("1040")) {//担保合同
            contractType = SysConstant.CONTRACT_TYPE_FIVE;
        } else if (type.equals("1030")) {//抵押合同
            contractType = SysConstant.CONTRACT_TYPE_THREE;
        } else if (type.equals("1018")) {//委托划扣授权书
            contractType = SysConstant.CONTRACT_TYPE_SEVEN;
        } else if (type.equals("1019")) {//还款承诺函
            contractType = SysConstant.CONTRACT_TYPE_SIX;
        }
        //删除老合同
        Contract contract = certificationOrderMapper.getCertificationContract(thirdPartyOrderId, contractType);
        if (contract == null)
            throw new XkdException("该订单未生成合同");
        fileService.fileRemove(contract.getContract());
        //下载新合同
        byte[] decodedBytes = Base64.getDecoder().decode(base64);
        String baseUrl = localPathDir + contractUrl + "/" + contract.getCompanyId() + "/";
        String filePath = contract.getContractNo() + ".pdf";
        String fileUrl = baseUrl + filePath;//文件下载路径
        File dirFile = new File(baseUrl);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }
        try (FileOutputStream fos = new FileOutputStream(fileUrl)) {
            fos.write(decodedBytes);
            fos.flush();
        } catch (IOException e) {
            log.error("公证合同文件保存失败", e);
            throw new XkdException(e.getMessage());
        }
        contractMapper.update(new Contract().setStatus("2").setContractTime(new Date()),
                new LambdaQueryWrapper<Contract>().eq(Contract::getContractId, contract.getContractId()));

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void acceptNotarization(com.alibaba.fastjson.JSONObject json) {
        com.alibaba.fastjson.JSONObject body = getCertificationData(json);
        String thirdPartyOrderId = body.getString("thirdPartyOrderId");//商户订单
        String fileName = body.getString("fileName");//合同类型
        String base64 = body.getString("base64");//文件base64
        String notaryNum = body.getString("notaryNum");//文件base64
        CertificationOrder certificationOrder = certificationOrderMapper.selectOne(new LambdaQueryWrapper<CertificationOrder>().eq(CertificationOrder::getOrderNo, thirdPartyOrderId));
        //下载公证书
        byte[] decodedBytes = Base64.getDecoder().decode(base64);
        String baseUrl = localPathDir + uploadMortgageInfo + "/" + certificationOrder.getCompanyId() + "/";
        String fileUrl = baseUrl + fileName;//文件下载路径
        File dirFile = new File(baseUrl);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }
        try (FileOutputStream fos = new FileOutputStream(fileUrl)) {
            fos.write(decodedBytes);
            fos.flush();
        } catch (IOException e) {
            log.error("公证书保存失败", e);
            throw new XkdException(e.getMessage());
        }
        Certification certification = new Certification();
        certification.setCertificationId(certificationOrder.getCertificationId());
        certification.setStatus(SysConstant.CERTIFICATION_STATUS_TOW);
        certification.setEndTime(new Date());
        certification.setNotaryNum(notaryNum);
        certification.setCertificate(uploadMortgageInfo + "/" + certificationOrder.getCompanyId() + "/" + fileName);
        certificationMapper.updateById(certification);
        certificationOrderMapper.updateStatus(SysConstant.CERTIFICATION_STATUS_TOW, certificationOrder.getOrderNo());
        //修改进件状态
        Integer incomingId = certificationOrder.getIncomingId();
        IncomingInfo info = incomingInfoMapper.selectById(incomingId);

        String productType = incomingInfoMapper.getProductType(incomingId);
        if (productType.equals(SysConstant.PRODUCT_TWO)) {//单录如果是车抵贷 到签约完成进行抵押
            outInfoMapper.updateStatus(SysConstant.BUSINESS_STATUS_SEVEN, certificationOrder.getOutId());
        } else {//单录公证无抵押 直接到待放款
            outInfoMapper.updateStatus(SysConstant.BUSINESS_STATUS_ELEVEN, certificationOrder.getOutId());
        }
        OutInfo outInfo = outInfoMapper.selectById(certificationOrder.getOutId());
        //扣除合同服务费
        Integer count = contractMapper.selectCount(new LambdaQueryWrapper<Contract>()
                .eq(Contract::getOutId, certificationOrder.getOutId())
                .in(Contract::getType, SysConstant.CONTRACT_TYPE_TOW, SysConstant.CONTRACT_TYPE_THREE, SysConstant.CONTRACT_TYPE_FIVE,
                        SysConstant.CONTRACT_TYPE_SIX, SysConstant.CONTRACT_TYPE_SEVEN));
        if (count == 0)
            log.info("该订单未生成合同");
        for (int i = 0; i < count; i++) {
            iCompanyService.deductingBalanceMain(null, null, incomingId, null, SysConstant.BUSINESS_FEE_FOUR, null, null, null);
        }
        //扣除公证服务费
        iCompanyService.deductingBalanceMain(outInfo, info.getIncomingOrder(), incomingId, null, SysConstant.BUSINESS_FEE_THREE, null, null, null);
    }

    @Override
    public void signFailReason(com.alibaba.fastjson.JSONObject json) {
        com.alibaba.fastjson.JSONObject body = getCertificationData(json);
        String thirdPartyOrderId = body.getString("thirdPartyOrderId");//商户订单
        String reason = body.getString("reason");//重签原因
        certificationOrderMapper.signFailReason(thirdPartyOrderId, reason);
    }

    private com.alibaba.fastjson.JSONObject getCertificationData(com.alibaba.fastjson.JSONObject json) {
        String appId = json.getString("appId");
        if (!appId.equals(notifyAppid))
            throw new XkdException("appId错误");
        String data = json.getString("data");
        String s = Sm4Util.decryptEcb(notifySm4key, data);
        return com.alibaba.fastjson.JSONObject.parseObject(s);
    }

    //验证签名
    public JSONObject getData(String app_id,
                              String sign_type,
                              String client_trans_id,
                              String trans_timestamp,
                              String trans_type,
                              String callback_url,
                              String version,
                              String data,
                              String sign) throws IOException {
        //验签
        TreeMap<String, String> mapResult = new TreeMap<>();
        mapResult.put("app_id", app_id);
        mapResult.put("sign_type", sign_type);
        mapResult.put("client_trans_id", client_trans_id);
        mapResult.put("trans_timestamp", trans_timestamp);
        mapResult.put("trans_type", trans_type);
        mapResult.put("callback_url", callback_url);
        mapResult.put("version", version);
        mapResult.put("data", data);
        String signStr = Signer.concatTreeMapParam(mapResult);//生成待验签字符串
        log.info("待验签字符：{}", signStr);
        Boolean bool = Verifier.verifyByCerFile(signStr, sign, cerPath);
        log.info("验签结果{}", bool);
        if (!bool)
            throw new XkdException("验签失败");
        String s = Signer.Base64Decode(data);
        log.info("业务响应结果{}", s);
        return JSONObject.fromObject(s);
    }

}
